

package functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.program;

import java.io.File;
import functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.units.OntologyType;

/**
 * The set of command line arguments that the program takes.
 * @author Jamie MacPherson
 */
public enum Argument {

    GOAFILE("g", 1),
    SIMILARITIESFILE("s", 1),
    RESULTSFILE("r", 1),
    OBOFILE("b", 1),
    SUBJECTGENESFILE("d", 1),
    THREADS("t", 2),
    PROGRAM("p", 3),
    ONTOLOGY("o", 4);
    

    private final String tag;
    private final int argumentType;
    public static final int FILE_ARGUMENT = 1;
    public static final int INT_ARGUMENT = 2;
    public static final int PROGRAM_ARGUMENT = 3;
    public static final int ONTOLOGY_ARGUMENT = 4;

    /**
     * The constructor takes a tag and an argument type.
     * The tag can be used on the command line to precede the value for that argument,
     * as can the name of the Argument.
     * @param tag a single character that can be used on the command line to precede the value for
     * the argument, e.g., the thread tag would appear on the command line as "-t" followed by an integer value
     * denoting the number of threads.
     * @param argumentType an integer value that is a 1 if the argument requires a file-path input, a 2
     * if the argument requires an integer input, a 3 if the argument requires one of the programs ("similarities" or "geneSetAnalysis"),
     * or a 4 if the object requires a GO ontology tag (one of "P", "C" or "F").
     */


    private Argument(String tag, int argumentType) {
        this.tag = tag;
        this.argumentType = argumentType;
    }

    /**
     * Get the tag of the argument.
     * @return the tag
     */
    public String getTag() {
        return tag;
    }

    /**
     * Gets an integer that denotes the type of value that the argument requires - a 1 if the argument requires a file-path input, a 2
     * if the argument requires an integer input, a 3 if the argument requires one of the programs ("distances" or "geneSetAnalysis"),
     * @return the integer that denotes the argument type
     */
    public int getArgumentType() {
        return argumentType;
    }

    /**
     * Gets the Argument object corresponding either to the tag (as from the <code>getTag()</code> method), or just the name
     * of the Argument (from the <code>getName()</code> method).
     * @param argumentString the string that may contain the tag or name of the argument.
     *
     * @return either an Argument if a match is found or <code>null</code> if no match is found.
     */
    public static Argument getArgument(String argumentString){
        for(Argument argument : Argument.values()){
            if(argumentString.equalsIgnoreCase(argument.name()) || argumentString.equalsIgnoreCase(argument.tag)){
                return argument;
            }
        }
        return null;
    }

    /**
     * Returns an Object derived from the String passed to the argument, of varying type depending on the value of the argumentType integer.
     * @param argumentValue the String value that the argument stores
     * @return an Object of appropriate type.
     */
    public Object getArgumentValue(String argumentValue){
        if(this.getArgumentType() == FILE_ARGUMENT){
            return getFile(argumentValue);
        } else if(this.getArgumentType() == INT_ARGUMENT){
            return getInt(argumentValue);
        } else if(this.getArgumentType() == ONTOLOGY_ARGUMENT){
            return getOntologyType(argumentValue);
        } else if(this.getArgumentType() == PROGRAM_ARGUMENT){
            return getProgram(argumentValue);
        }
        return null;
    }

    /**
     *
     * returns a new file from a String that should contain a file path.
     */

    private File getFile(String argumentValue) {
        return new File(argumentValue);
    }

    /**
     * returns an integer parsed from the string that is passed to the argument.
     */
    private Integer getInt(String argumentValue) {
        Integer i = null;
        try {
            i = Integer.parseInt(argumentValue);
        } catch(NumberFormatException exception){
            System.out.println("The value given for the argument: "+this.name()+" (-"+this.getTag()+") needs to be an integer, you gave: "+argumentValue);
            System.out.println("exiting program");
            exception.printStackTrace();
            System.exit(0);
        }
        return i;
    }

    /**
     * Returns an <code>OntologyType</code> object from a string if it is equal to the value of the <code>getOntologyFromTag()</code>
     * method of the Ontology type.
     * @param argumentValue the string that should be equal to one of the values from the <code>getOntologyFromTag()</code>
     * method from an <code>OntologyType</code> object.
     * @return the <code>OntologyType</code> corresponding to the given string.
     */
    private OntologyType getOntologyType(String argumentValue) {
        OntologyType ontologyType = null;
        try {
            ontologyType = ontologyType.getOntologyFromTag(argumentValue);
        } catch(IllegalArgumentException exception){
            System.out.println("The value given for the argument: "+this.name()+" (-"+this.getTag()+") needs to be one of 'P', 'F' or 'C', you gave: "+argumentValue);
            System.out.println("exiting program");
            exception.printStackTrace();
            System.exit(0);
        }
        return ontologyType;
    }

    /**
     * Returns an <code>ProgramType</code> object from a string if it is equal to the value of the <code>getProgramFromTag()</code>
     * method of the Ontology type.
     * @param argumentValue the string that should be equal to one of the values from the <code>getProgramFromTag()</code>
     * method from an <code>ProgramType</code> object.
     * @return the <code>ProgramType</code> corresponding to the given string.
     */
    private ProgramType getProgram(String argumentValue) {
        ProgramType program = null;
        try {
            program = program.getProgramFromTag(argumentValue);
        } catch(IllegalArgumentException exception){
            System.out.println("The value given for the argument: "+this.name()+" (-"+this.getTag()+") needs to be one of 'pvalues' or 'distances' you gave: "+argumentValue);
            System.out.println("exiting program");
            exception.printStackTrace();
            System.exit(0);
        }
        return program;
    }


    



}
